/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 * ***************************************************************************/




#if !defined(AFX_PGLREGION_H__DAD08248_1E11_4C95_A77D_4968F1077BFD__INCLUDED_)
#define AFX_PGLREGION_H__DAD08248_1E11_4C95_A77D_4968F1077BFD__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <pgl/core/PGLPave.h>
#include <pgl/core/PGLView2D.h>
#include <pgl/core/PGLAxe.h>
#include <pgl/core/PGLObjectManager.h>
#include <pgl/core/PGLLegend.h>


/*!
	\defgroup PGLRegionGroup Graphical regions (such as graph, sub-plots)
	\ingroup PGLObjectGroup
*/

class CPGLRegion;

/*! \brief An object container - manager

\ingroup PGLManagerGroup
*/
class PGLCORE_EXT_CLASS CPGLRegionManager : public TObjectPtrContainer< CPGLRegion >
{
public:
	//! \name Finding pointed region by point
	//@{
	//! return the address of the top-most region that contains point, NULL otherwize
	long FindPointedRegion(gfxinterface::CGfxInterface &gfx, const CPGLPointD &point);
	//@}

	//! \name Serialization and debugging
	//@{
	//! Serialization
	virtual void SerializeXML(CPGLArchive& ar);
	//@}
};


/*! \brief A base class to create graphic regions.

\ingroup PGLRegionGroup
This is the base class for all graphical regions. It controls common carateristics
of all graphical objects but also has added features to handle the view, resizing.
*/
class PGLCORE_EXT_CLASS CPGLRegion : public CPGLPave
{
PGL_DECLARE_DYNCREATE(CPGLRegion);
public:
	//! \name Constructors
	//@{
	//! Constructor
	CPGLRegion();
	//! Copy constructor
	CPGLRegion(const CPGLRegion& r){*this=r;};
	//! Assignement constructor
	CPGLRegion& operator =(const CPGLRegion& g);
	//! Destructor
	virtual ~CPGLRegion();
	//! Delete all objects in graph and destroy it.
	virtual void Delete();
	//@}

	//! \name GUI
	//@{
	//! Adds item to the property trees
	virtual HTREEITEM AddPropTree(CTreeCtrl* pTree, HTREEITEM hParent);
	//! Adds property page
	virtual void AddPropertyPage(CPropertySheet* pPropSheet);
	//@}

	//! \name Setters and getters
	//@{
	//! Gets a pointer to the axis object.
	CPGLAxe2D* GetAxe()										{	return &m_axe;};
	//! returns a pointer to the object manager. Use with care.
	CPGLObjectManager& GetObjectManager();
	//! returns a pointer to the object manager, const
	const CPGLObjectManager& GetObjectManager()	const;
	//! returns a reference to the child manager
	CPGLRegionManager& GetChildManager();
	//! returns a reference to the child manager, const
	const CPGLRegionManager& GetChildManager() const;
	//@}

	//! \name Clipboard
	//@{
	//!  unhide all objects in the graph
	void UnhideAll();
	//@}

	//! \name Child region methods
	//@{	
	//! Create an array of region childs from top to bottom, left to right.
	void Divide(int nrows, int ncols);
	/*! \brief Divide the region according to the layout

	\param szXMLLayout xml string describing the layout.
	\return true if succesful

	The string szXMLLayout described a layout.
	\par Nodes and attributes
		- <b>matrix</b> : matrix of regions,
			#- nrows, number of rows, default is 1
			#- ncols, number of columns, default is 1
			#- xpos, vector of x positions (from left to right)
			#- ypos, vector of y positions (from top to bottom)
		- <b>child</b>: sub child
			#- index, index of the child to modify

	\par Examples:
	*/
	bool Layout(LPCTSTR szXMLLayout);
	//! Returns the number of region childs
	size_t GetNChilds() const		{	return GetNChildren();};
	//! Returns the number of region childs (in correct english)
	size_t GetNChildren() const;
	//! Returns the i-th child. NULL if out of bound.
	CPGLRegionPtr GetChild(size_t i);
	//! Delete i-th child (if existing)
	void DeleteChild(size_t i);
   
   //! Delete child region (if existing) 
   // Delete all objects owned by it as well
   void DeleteChildWithObjects(CPGLRegionPtr regionPtr);

	//! Create a child at the front of the plot and returns the pointer
	CPGLRegionPtr AddRegion();
	//! Create a child at the back of the plot and returns the pointer
	CPGLRegionPtr AddRegionBack();
	/*! \brief Adds a legend to the region
	
	\param eLegendPos position of the new legend. Default is upper right.
	
	Create a legend, attach all current object to it and add it to object pile.
	*/
	CPGLLegendPtr AddLegend();
	//@}

	//! \name Object list
	//@{
	//!  adds pObject to the front of the graph (memory must be allowed by user)
	void AddObject(CPGLObjectPtr pObject);
	//!  adds pObject to the back of the graph (memory must be allowed by user)
	void AddObjectBack(CPGLObjectPtr pObject);
	//! Delete all graphical objects
	virtual void DeleteAllObjects();
	//! Delete i-th object (if existing)
	void DeleteObject(size_t i);
	//! Finds the region pointed by the mouse
	long FindPointedRegion(gfxinterface::CGfxInterface& gfx, const CPGLPointD& point);
	//@}

	//! \name Miscelanous
	//@}
	/*! \brief Loads a Common Separated Value file

	Load a text file of data formated as follows:
	\code
	arg_1, arg_2, ... arg_n
	value_11, val_12, ..., val_1n
	...
	value_m1, ....	, val_mn
	\endcode
	where 
		- arg_i are the variable names
		- value_ij are columns of data

	By default, data and variable name have to be separated by a comma !
	*/	
	bool LoadCSVFile( LPCTSTR szFileName);
	//@}	

	//!\name View manipulation
	//@{
	/*! \brief Sets viewport dimensions.

	\param tx lower left position (in pixels)
	\param ty upper left position (in pixels)
	\param width width of view (in pixels)
	\param height height of view (in pixels)
	\sa CPGLView::SetViewport
	\sa CPGLView2D::SetViewport
	*/
	void SetViewport(int tx, int ty, int width, int height);

	/*! Returns viewport dimensions

	\param vp a double[4]
	\retval vp tx,ty,width,height
	\sa SetViewport
	*/
	void GetViewport(int* vp)				{	vp[0]=m_view.GetTx(); vp[1]=m_view.GetTy(); vp[2]=m_view.GetWidth(); vp[3]=m_view.GetHeight();};

	//! Sets the normalized bounding box
	void SetNormBBox(const CPGLRectD& rNormBBox);
	//! Sets the normalized bounding box
	void SetNormBBox(float llx, float lly, float urx, float ury);	
	
	//!  sets the view object
	void SetView(const CPGLView2D& pView)	{	m_view=pView;};
	//!  returns the view object
	CPGLView2D* GetView()						{	return &m_view;};

	/*! \brief Push world, clipping and bounding box in gfx

	Each call to PushWorldClipBBox must be called by a call to PopWorldClipBBox. These calls must be
	enclosed a BeginPaint - EndPaint of gfx.
	*/
	void PushWorldClipBBox(gfxinterface::CGfxInterface& gfx);
	/*! Pops world, clipping and bounding box in gfx

	Restore world view, clipping rect and bounding box before the call to PushWorldClipBBox.
	\sa PushWorldClipBBox
	*/
	void PopWorldClipBBox(gfxinterface::CGfxInterface& gfx);

	/*! \brief Refresh the view.

	Refresh the view by recomputing margins, clip borders, etc... The extent in world coordinates are not 
	modified by this method.

	\param bRecurse true to refresh child chars
	\param bRefreshAxis true to refresh axis numbering (get prettier numbers)
	*/
	void RefreshView(gfxinterface::CGfxInterface& gfx, bool bRecurse = false, bool bRefreshAxis = false);

	/*! \brief Move view.
	
	Translate view of \a x pixels horizontaly and \a y verticaly. The view
	limits are updated and axe limits are modified accordingly.
	\sa CPGLView::Pan
	\sa CPGLView2D::Pan
	\sa CPGLAxe2D::Pan
	\sa ZoomAll
	\sa ZoomBox
	\sa ZoomRegion
	\sa ZoomIn
	\sa ZoomOut
	*/
	virtual void Pan(int x, int y);

	//! Scale the view
	void ZoomScale(double x, double y);
	
	/*! \brief Zooms out.
	
	Extends the limits of the view. The axe limits are "processed" and
	the view limits are modified accordingly.
	\sa CPGLView::ZoomOut
	\sa CPGLView2D::ZoomOut
	\sa GrowExt
	\sa CPGLView2D::ZoomRegion
	\sa ZoomAll
	\sa ZoomBox
	\sa ZoomRegion
	\sa ZoomIn
	\sa Pan
	*/	
	virtual void ZoomOut(gfxinterface::CGfxInterface& gfx);

	/*! \brief Zooms in.
	
	Extends the limits of the view. The axe limits are "processed" and
	the view limits are modified accordingly.
	\sa CPGLView::ZoomOut
	\sa CPGLView2D::ZoomOut
	\sa GrowExt
	\sa Pan
	\sa ZoomAll
	\sa ZoomBox
	\sa ZoomRegion
	\sa ZoomOut
	*/	
	virtual void ZoomIn(gfxinterface::CGfxInterface& gfx);

	/*! \brief Show all objects.
	
	Extends the limits to show all objects. The axe limits are "processed" and
	the view limits are modified accordingly.
	\sa GrowExt
	\sa Pan
	\sa ZoomBox
	\sa ZoomRegion
	\sa ZoomIn
	\sa ZoomOut
	*/	
	virtual void ZoomAll(gfxinterface::CGfxInterface& gfx, bool recurse = false);

	/*! \brief Zooms a region in view units.
	
	  \param pExt {left, right, bottom , top}
	Extends the limits to region describe in \a pExt. 
	The axe limits are "processed" and
	the view limits are modified accordingly.
	\sa GrowExt
	\sa Pan
	\sa ZoomBox
	\sa ZoomAll
	\sa ZoomIn
	\sa ZoomOut
	*/	
	virtual void ZoomRegion(gfxinterface::CGfxInterface& gfx, CPGLRectD& rExt);

	/*! \brief Zooms a region in viewport unit.
	
	Extends the limits to region describe by the box of opposite
	summit (\a xStart, \a yStart) - (\a xEnd \a yEnd). 
	The axe limits are "processed" and
	the view limits are modified accordingly.
	\sa GrowExt
	\sa Pan
	\sa ZoomBox
	\sa ZoomAll
	\sa ZoomIn
	\sa ZoomOut
	*/	
	virtual void ZoomBox(gfxinterface::CGfxInterface& gfx,int xStart,int yStart,int xEnd,int yEnd);
	//@}

	//! \name Update methods
	//@{
	//! Set updating graph at next draw
	void PostUpdateGraph()		{	m_bNeedUpdate=TRUE; PostUpdateExtent();};
	//! Returns true if region needs update
	bool NeedUpdate()			{	return m_bNeedUpdate;};
	//! Update graph.
	virtual void UpdateGraph(gfxinterface::CGfxInterface& gfx);
	//@}

	//! \name Region rotation
	//@{
	//! setting angle in radians
	void SetAngle(double _dAngle)	{	m_dAngle = _dAngle;};
	//! returns angle in radians
	double GetAngle() const			{	return m_dAngle;};
	//@}

	//! \name Virtual plot override
	//@{

	/*! \brief Gets the extents of the graph

	\retval {{left, right, bottom, top }

	Computes and returns the extents of all objects in the graph.
	\sa CPGLObject::GetExtent
	\sa ZoomAll
	\sa ZoomBox
	\sa ZoomRegion
	\sa ZoomIn
	\sa ZoomOut
	*/
	virtual void GetUnionExtent(gfxinterface::CGfxInterface& gfx, CPGLRectD& rExtent);

	/*! \brief plots the graph to DC

	\param renderToSelect This boolean controls the selection process.

	If you want to select object, i.e. you want them to load thier ID in the selection
	buffer, you set this value to TRUE, otherwise FALSE.
	*/
	virtual void PlotGfx(gfxinterface::CGfxInterface& gfx);
	//@}

	//! \name Object and child order
	//@{
	//! return true if child are drawed before objects
	bool IsChildFirst() const							{	return m_bChildFirst;};
	//! sets the child - object drawing order, default is false
	void SetChildFirst( bool bChildFirst = true )		{	m_bChildFirst = bChildFirst;};
	//@}

	//! \name Scripting
	//@{
	//@}

	//! \name  Serialization and debugging
	//@{
	//! Serialization
	virtual void SerializeXML(CPGLArchive& ar);
	#ifdef _DEBUG
		//! MFC Dump
	    virtual void Dump( CDumpContext& dc ) const;
	    //! MFC AssertValid
	    virtual void AssertValid() const; 
	#endif
	//@}
	
private:
	//! \name Attributes
	//@{
	//!  object manager
	CPGLObjectManager m_mObjects;
	//!  child regions manager
	CPGLRegionManager m_mChilds;
	//!  an x-y axe
	CPGLAxe2D m_axe;
	//!  the view describing the graph (viewport + extent)
	CPGLView2D m_view;
	//! angle
	double m_dAngle;
	//! true if child region have to be drawed before objects, default is false
	bool m_bChildFirst;
	//!  TRUE if graph needs update
	bool m_bNeedUpdate;
	//@}
};

PGL_DECLARE_SMARTPTR( CPGLRegion );

/*! \example subplot.cpp

This example demonstrate subplotting tools.
\image html subplot.png "Subplotting. Subplotting can be done recursively in PGL to achieve complex charting."
*/

#endif // !defined(AFX_PGLREGION_H__DAD08248_1E11_4C95_A77D_4968F1077BFD__INCLUDED_)

/*
//!  test if there's anything in clipboard, return TRUE if empty
inline bool CPGLRegion::IsClipBoardEmpty() 
{
	if (sm_mClipboard==NULL)
		return TRUE;

	ASSERT_VALID(sm_mClipboard);
	return sm_mClipboard->IsEmpty(); 
};
*/
